#!/usr/bin/python

import numpy as np

from scipy.sparse import lil_matrix
from scipy.spatial.kdtree import KDTree

def get_noise(stddev=0.25, numpoints=150):
    # 2d gaussian random noise
    x = np.random.normal(0, stddev, numpoints)
    y = np.random.normal(0, stddev, numpoints)
    return np.column_stack((x, y))

def get_circle(center=(0.0, 0.0), r=1.0, numpoints=150):
    # use polar coordinates to get uniformly distributed points
    step = np.pi * 2.0 / numpoints
    t = np.arange(0, np.pi * 2.0, step)
    x = center[0] + r * np.cos(t)
    y = center[1] + r * np.sin(t)
    return np.column_stack((x, y))

def radial_kernel(c=1.5):
    def inner(a, b):
        d = a - b
        return np.exp((-1 * (np.sqrt(np.dot(d, d.conj()))**2)) / c)
    return inner

def circle_samples():
    circles = []
    for radius in (1.0, 2.8, 5.0):
        circles.append(get_circle(r=radius) + get_noise())
    return np.vstack(circles)

def mutual_knn(points, knn=10, distance=radial_kernel()):
    n = len(points)
    W = lil_matrix((n, n))
    kt = KDTree(points)
    for i, point in enumerate(points):
        # cannot use euclidean distance directly
        for neighbour in kt.query(point, knn + 1)[1]:
            if i != neighbour:
                W[i, neighbour] = distance(point, points[neighbour])
    return W

def rename_clusters(idx):
    # so that first cluster has index 0
    num = -1
    seen = {}
    newidx = []
    for id in idx:
        if id not in seen:
            num += 1
            seen[id] = num
        newidx.append(seen[id])
    return np.array(newidx)
